package com.springBoot.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;

/**
 * @author chenkuan
 * @version v1.0
 * @desc 导出CSV文件
 * @date 2019/11/11 011 18:31
 */
@Component
public class ExportCSVUtil<T> {

	private Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * CSV文件生成
	 *
	 * @param title    文件名
	 * @param headers  头部标题行
	 * @param renders  表格标题对应的字段集合
	 * @param dataList 数据
	 * @param response 响应
	 */
	public void exportCSV(String title, List<String> headers, List<String> renders, Collection<T> dataList, HttpServletResponse response) {
		BufferedWriter csvWriter = null;
		try {
			response.setContentType("application/octet-stream");
			String fileName = title + ".csv";
			fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", " "); //解决编码后空格变 + 号
			response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
			// 创建BufferedWriter写入流
			csvWriter = new BufferedWriter(new OutputStreamWriter(response.getOutputStream(), "UTF-8"));
			// 添加BOM头，解决微软excel中文乱码
			csvWriter.write(new String(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}));
			// 写入文件头部
			writeRow(headers, csvWriter);
			// 写入文件内容
			for (T data : dataList) {
				writeRow(data, renders, csvWriter);
			}
			csvWriter.flush();
		} catch (Exception e) {
			logger.error("Create CSV Exception", e);
			throw new RuntimeException("Create CSV Exception");
		} finally {
			if (csvWriter != null) {
				try {
					csvWriter.close();
				} catch (IOException e) {
					logger.error("CSVWriter Stream Close Exception", e);
				}
			}
		}
	}

	/**
	 * 写一行数据到头部
	 *
	 * @param headers   数据
	 * @param csvWriter 文件写入流
	 */
	private void writeRow(List<String> headers, BufferedWriter csvWriter) throws IOException {
		// 写入标题
		StringBuilder builder = new StringBuilder();
		for (String header : headers) {
			builder.append("\"").append(header).append("\",");
		}
		csvWriter.write(builder.toString());
		csvWriter.newLine();
	}

	/**
	 * 写一行对象数据
	 *
	 * @param t         数据对象
	 * @param renders   表格标题对应的字段集合
	 * @param csvWriter 文件写入流
	 */
	private void writeRow(T t, List<String> renders, BufferedWriter csvWriter) throws IOException, NoSuchFieldException, IllegalAccessException {
		// 写入内容
		StringBuilder builder = new StringBuilder();
		Object value;
		for (String fieldStr : renders) {
			Field field = t.getClass().getDeclaredField(fieldStr);
			field.setAccessible(true);
			value = field.get(t);
			boolean isNumeric = false;
			if (value != null && Number.class.isAssignableFrom(field.getType())) {
				value = new BigDecimal(value.toString()).stripTrailingZeros().toPlainString();
			} else if (value != null && isNumeric(value.toString())) {
				//解决纯数字在excel中打开数字前面的0丢失
				isNumeric = true;
			}
			builder.append("\"");
			builder.append(value == null ? "" : value);
			if (isNumeric) {
				builder.append("\t");
			}
			builder.append("\",");
		}
		csvWriter.write(builder.toString());
		csvWriter.newLine();
	}

	private static boolean isNumeric(String str) {
		Pattern pattern = Pattern.compile("[0-9]*");
		return pattern.matcher(str).matches();
	}
}
